#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <ncurses.h>
#include <stdlib.h>
//comment
#define BUFFER_MAX 3
#define DIRECTION_MAX 35
#define VALUE_MAX 30

#define IN   0
#define OUT  1

#define LOW  0
#define HIGH 1

#define POUT1 17 
#define POUT2 18
#define POUT3 27
#define POUT4 22
#define POUT5 23
#define POUT6 24
#define POUT7 25

#define FAIL -1
#define NOT_PRESSED 0
#define PRESSED 1

int GPIOExport(int pin)
{
        char buffer[BUFFER_MAX];
        ssize_t bytes_written;
        int fd;

        fd = open("/sys/class/gpio/export", O_WRONLY);
        if (-1 == fd) {
                fprintf(stderr, "Failed to open export for writing!\n");
                return(-1);
        }

        bytes_written = snprintf(buffer, BUFFER_MAX, "%d", pin);
        write(fd, buffer, bytes_written);
        close(fd);
        return(0);
}

int GPIOUnexport(int pin)
{
        char buffer[BUFFER_MAX];
        ssize_t bytes_written;
        int fd;

        fd = open("/sys/class/gpio/unexport", O_WRONLY);
        if (-1 == fd) {
                fprintf(stderr, "Failed to open unexport for writing!\n");
                return(-1);
        }

        bytes_written = snprintf(buffer, BUFFER_MAX, "%d", pin);
        write(fd, buffer, bytes_written);
        close(fd);
        return(0);
}

int GPIODirection(int pin, int dir)
{
        static const char s_directions_str[]  = "in\0out";

        char path[DIRECTION_MAX];
        int fd;

        snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/direction", pin);
        fd = open(path, O_WRONLY);
        if (-1 == fd) {
                fprintf(stderr, "Failed to open gpio direction for writing!\n");
                return(-1);
        }

        if (-1 == write(fd, &s_directions_str[IN == dir ? 0 : 3], IN == dir ? 2 : 3)) {
                fprintf(stderr, "Failed to set direction!\n");
                return(-1);
        }

        close(fd);
        return(0);
}

int GPIORead(int pin)
{
        char path[VALUE_MAX];
        char value_str[3];
        int fd;

        snprintf(path, VALUE_MAX, "/sys/class/gpio/gpio%d/value", pin);
        fd = open(path, O_RDONLY);
        if (-1 == fd) {
                fprintf(stderr, "Failed to open gpio value for reading!\n");
                return(-1);
        }

        if (-1 == read(fd, value_str, 3)) {
                fprintf(stderr, "Failed to read value!\n");
                return(-1);
        }

        close(fd);

        return(atoi(value_str));
}

void GPIOWrite(int pin, int value)
{
	static const char s_values_str[] = "01";
	char path[VALUE_MAX];
	int fd;

	snprintf(path, VALUE_MAX, "/sys/class/gpio/gpio%d/value", pin);
	fd = open(path, O_WRONLY);

	if (-1 == fd)
	{
		fprintf(stderr, "Failed to open gpio value for writing!\n");
		exit(EXIT_FAILURE);
	}

	if (1 != write(fd, &s_values_str[LOW == value ? 0 : 1], 1))
	{
		fprintf(stderr, "Failed to write value!\n");
		exit(EXIT_FAILURE);
	}

	close(fd);
}
/*
int my_getch()
{
        int             ch;
        struct termios  old;
        struct termios  tmp;

        if (tcgetattr(STDIN_FILENO, &old))
        {
                return -1;
        }

        memcpy(&tmp, &old, sizeof(old));

        tmp.c_lflag &= ~ICANON & ~ECHO;

        if (tcsetattr(STDIN_FILENO, TCSANOW, (const struct termios*) &tmp))
        {
                return -1;
        }

        ch = getchar();

        tcsetattr(STDIN_FILENO, TCSANOW, (const struct termios*) &old);

        return ch;
}
*/
int main(int argc, char *argv[])
{	
	int blinkCounter=0;
	int ch = -1;
	int repeat = 9;
	int poutN;
	int status1 = NOT_PRESSED, status2 = NOT_PRESSED, status3 = NOT_PRESSED,
		status4 = NOT_PRESSED, status5 = NOT_PRESSED, status6 = NOT_PRESSED,
		status7 = NOT_PRESSED;
	int statusBlinkPattern=0;

	/* Enable GPIO pins */
	if (FAIL == GPIOExport(POUT1) || FAIL == GPIOExport(POUT2) || FAIL == GPIOExport(POUT3) || 
			FAIL == GPIOExport(POUT4) || FAIL == GPIOExport(POUT5) ||
			FAIL == GPIOExport(POUT6) || FAIL == GPIOExport(POUT7)) 
	{
		printf("Failed to enable GPIO pins\n");
		return FAIL;
	}

	/* Set GPIO directions */
	if (FAIL == GPIODirection(POUT1, OUT) || FAIL == GPIODirection(POUT2, OUT) ||
			FAIL == GPIODirection(POUT3, OUT) || FAIL == GPIODirection(POUT4, OUT) ||
			FAIL == GPIODirection(POUT5, OUT) || FAIL == GPIODirection(POUT6, OUT) ||
			FAIL == GPIODirection(POUT7, OUT))
	{
		printf("Failed to set GPIO  direction\n");
		return FAIL;
	}

	/* Curses Initialisations */
	initscr();
	raw();
	keypad(stdscr, TRUE);
	noecho();

	printw("================================================================================\n");
	printw("Press 'q' to Exit\n");

	printw("Available commands:\n");

	printw("\t'a': all leds ON\n");
	printw("\t'0': all leds OFF\n");
	printw("\t'1-7': led[1-7] OFF/ON\n");
	
	printw("\t'p': led blink pattern\n");
	
	
	while(1)
	{	
		timeout(1);	
		ch=getch();
		if(ch == 'q')
		{
			GPIOWrite(POUT1, LOW);
                        GPIOWrite(POUT2, LOW);
                        GPIOWrite(POUT3, LOW);
                        GPIOWrite(POUT4, LOW);
                        GPIOWrite(POUT5, LOW);
                        GPIOWrite(POUT6, LOW);
                        GPIOWrite(POUT7, LOW);

			break;	
		}

		if(statusBlinkPattern){
			//usleep(1000);
			blinkCounter=blinkCounter+1;

		
		// specify each blink led
		
			if(blinkCounter%50==0){
				GPIOWrite(POUT4,GPIORead(POUT4)^HIGH);
			}
			if(blinkCounter%100==0)
			{
				GPIOWrite(POUT6,GPIORead(POUT6)^HIGH);
			}
			if(blinkCounter%200==0)
			{
				GPIOWrite(POUT2,GPIORead(POUT2)^HIGH);
			}
			if(blinkCounter%400==0)
			{
				GPIOWrite(POUT1,GPIORead(POUT1)^HIGH);
			}
			if(blinkCounter%800==0)
			{
				GPIOWrite(POUT5,GPIORead(POUT5)^HIGH);
			}
			if(blinkCounter%1600==0)
			{
				GPIOWrite(POUT3,GPIORead(POUT3)^HIGH);
			}
			if(blinkCounter%3200==0)
			{
				GPIOWrite(POUT7,GPIORead(POUT7)^HIGH);
			}
			if(blinkCounter>=6400)
			{
				blinkCounter=0;
			}
		}	



		switch(ch)
		{
			case '1':
				if (status1 == NOT_PRESSED) {GPIOWrite(POUT1, HIGH); status1 = PRESSED;}
				else {GPIOWrite(POUT1, LOW); status1 = NOT_PRESSED;}
				break;
			case '2':
				if (status2 == NOT_PRESSED) {GPIOWrite(POUT2, HIGH); status2 = PRESSED;}
				else {GPIOWrite(POUT2, LOW); status2 = NOT_PRESSED;}
				break;
			case '3':
				if (status3 == NOT_PRESSED) {GPIOWrite(POUT3, HIGH); status3 = PRESSED;}
				else {GPIOWrite(POUT3, LOW); status3 = NOT_PRESSED;}
				break;
			case '4':
				if (status4 == NOT_PRESSED) {GPIOWrite(POUT4, HIGH); status4 = PRESSED;}
				else {GPIOWrite(POUT4, LOW); status4 = NOT_PRESSED;}
				break;
			case '5':
				if (status5 == NOT_PRESSED) {GPIOWrite(POUT5, HIGH); status5 = PRESSED;}
				else {GPIOWrite(POUT5, LOW); status5 = NOT_PRESSED;}
				break;
			case '6':
				if (status6 == NOT_PRESSED) {GPIOWrite(POUT6, HIGH); status6 = PRESSED;}
				else {GPIOWrite(POUT6, LOW); status6 = NOT_PRESSED;}
				break;
			case '7':
				if (status7 == NOT_PRESSED) {GPIOWrite(POUT7, HIGH); status7 = PRESSED;}
				else {GPIOWrite(POUT7, LOW); status7 = NOT_PRESSED;}
				break;
			case 'a':
                		GPIOWrite(POUT1, HIGH);
                		GPIOWrite(POUT2, HIGH);
                		GPIOWrite(POUT3, HIGH);
                		GPIOWrite(POUT4, HIGH);
                		GPIOWrite(POUT5, HIGH);
                		GPIOWrite(POUT6, HIGH);
				GPIOWrite(POUT7, HIGH);
				break;
			case '0':
                		GPIOWrite(POUT1, LOW);
                		GPIOWrite(POUT2, LOW);
                		GPIOWrite(POUT3, LOW);
                		GPIOWrite(POUT4, LOW);
                		GPIOWrite(POUT5, LOW);
                		GPIOWrite(POUT6, LOW);
				GPIOWrite(POUT7, LOW);
				break;
			case 'p':
				statusBlinkPattern=statusBlinkPattern^1;
			case KEY_DOWN:
				GPIOWrite(POUT1, HIGH);
				break;
			default:
				//printw("\nThe pressed key is ");
				//attron(A_BOLD);
				//printw("%c", ch);
				//attroff(A_BOLD);
				break;
		}

	}

	refresh();
	endwin();
         
	/* Disable GPIO pins */
	if (FAIL == GPIOUnexport(POUT1) || FAIL == GPIOUnexport(POUT2) || FAIL == GPIOUnexport(POUT3)
			FAIL == GPIOUnexport(POUT4) || FAIL == GPIOUnexport(POUT5) ||
			FAIL == GPIOUnexport(POUT6) || FAIL == GPIOUnexport(POUT7))
	{
		printf("Failed to disable GPIO pins\n");
		return FAIL;
	}

	return 0; 
}
